//
//  NKHealthKitManage.m
//  HealthDemo
//
//  Created by SongGang on 2017/3/13.
//  Copyright © 2017年 NK. All rights reserved.
//

#import "NKHealthKitManager.h"
#import <UIKit/UIDevice.h>
#import <CoreLocation/CoreLocation.h>
#import <CoreMotion/CoreMotion.h>
#import <MapKit/MapKit.h>

#define NKDevice [[[UIDevice currentDevice] systemVersion] doubleValue]
#define NKErrorWithInfo(value,key) [NSError errorWithDomain:@"com.nk.www" code:-1 userInfo:[NSDictionary dictionaryWithObject: value forKey:key]];
static NKHealthKitManager *manager;

@interface NKHealthKitManager() <CLLocationManagerDelegate>
@property (nonatomic, strong) void(^completion)(double altitude, double speed, NSString *direction);
@property (nonatomic, strong) CLLocationManager *manager;
@property (nonatomic, strong) CLLocation *oldLocation;
@property (nonatomic, strong) CMAltimeter *altimeter;

@end

@implementation NKHealthKitManager

- (CLLocationManager *)manager {

    if (!_manager) {
        
        CLLocationManager *manager = [[CLLocationManager alloc] init];
        // 导航精准度
        manager.desiredAccuracy = kCLLocationAccuracyBest;
        manager.delegate = self;
        // 前后台定位
        [manager requestAlwaysAuthorization];
        // 设置距离过滤器为0米，表示每移动0米更新一次位置
        manager.distanceFilter = kCLDistanceFilterNone;
        _manager = manager;
    }
    return _manager;
}

- (CMAltimeter *)altimeter {

    if (!_altimeter) {
        _altimeter = [[CMAltimeter alloc] init];
    }
    
    return _altimeter;
}

+ (instancetype)shareInstance {

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [[self alloc] init];
    });
    return manager;
    
}

- (void)authorizeHealthKit:(void(^)(BOOL success, NSError *error))compltion {

    // 系统8.0以上
    if (NKDevice > 8.0) {
        
        if (![HKHealthStore isHealthDataAvailable]) {
            
            NSError *error = NKErrorWithInfo(@"该设备不支持", NSLocalizedDescriptionKey);
            if (compltion != nil) {
                compltion(false,error);
            }
            return;
        }
        
        self.healthStore = [[HKHealthStore alloc] init];
        // 读写类型
        NSSet *writeDataSet = [self dataTypeToWrite];
        NSSet *readDataSet = [self dataTypesRead];
        
        // 注册需要读写的数据类型
        [self.healthStore requestAuthorizationToShareTypes:writeDataSet readTypes:readDataSet completion:^(BOOL success, NSError * _Nullable error) {
            if (compltion) {
            
                compltion(success,error);
            }
        }];
        
    }else {
    
        NSError *error = NKErrorWithInfo(@"系统低于8.0", NSLocalizedDescriptionKey);
        if (compltion) {
            
            compltion(false, error);
        }
    }
    
}

// 获取步数
- (void)getSetpCount:(void(^)(double value, NSError *error))completion {

    HKQuantityType *setpType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount];
    // 时间降序排列
    NSSortDescriptor *timeSortDescriptor = [[NSSortDescriptor alloc] initWithKey:HKSampleSortIdentifierEndDate ascending:NO];
    
    HKSampleQuery *sampleQuery = [[HKSampleQuery alloc] initWithSampleType:setpType predicate:[NKHealthKitManager predicateForSamplesToday] limit:HKObjectQueryNoLimit sortDescriptors:@[timeSortDescriptor] resultsHandler:^(HKSampleQuery * _Nonnull query, NSArray<__kindof HKSample *> * _Nullable results, NSError * _Nullable error) {
        
        if (error) {
            
            if (completion) {
                
                completion(0,error);
            }
            
        }else {
        
            NSInteger totleSteps = 0;
            for(HKQuantitySample *quantitySample in results)
            {
                HKQuantity *quantity = quantitySample.quantity;
                HKUnit *heightUnit = [HKUnit countUnit];
                double usersHeight = [quantity doubleValueForUnit:heightUnit];
                totleSteps += usersHeight;
            }
            if (completion) {
                
                completion(totleSteps,error);
            }
        }
    }];
    [self.healthStore executeQuery:sampleQuery];
}

// 获取公里数
- (void)getDistance:(void(^)(double value, NSError *error))completion
{
    HKQuantityType *distanceType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceWalkingRunning];
    NSSortDescriptor *timeSortDescriptor = [[NSSortDescriptor alloc] initWithKey:HKSampleSortIdentifierEndDate ascending:NO];
    HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:distanceType predicate:[NKHealthKitManager predicateForSamplesToday] limit:HKObjectQueryNoLimit sortDescriptors:@[timeSortDescriptor] resultsHandler:^(HKSampleQuery * _Nonnull query, NSArray<__kindof HKSample *> * _Nullable results, NSError * _Nullable error) {
        
        if(error)
        {
            if (completion) {
                
                completion(0,error);
            }
        }
        else
        {
            double totleSteps = 0;
            for(HKQuantitySample *quantitySample in results)
            {
                HKQuantity *quantity = quantitySample.quantity;
                HKUnit *distanceUnit = [HKUnit meterUnitWithMetricPrefix:HKMetricPrefixKilo];
                double usersHeight = [quantity doubleValueForUnit:distanceUnit];
                totleSteps += usersHeight;
            }
            
            if (completion) {
                
                completion(totleSteps,error);
            }
        }
    }];
    [self.healthStore executeQuery:query];
}

// 获取定位信息(海拔，移动速度，方向)
- (void)getLocation:(void(^)(double altitude, double speed, NSString *direction))completion {

    dispatch_sync(dispatch_get_main_queue(), ^{
        
        [self.manager startUpdatingLocation];
        _completion = completion;
        
    });
}

// 获取楼层
- (void)getLightsClimbed:(void(^)(double value, NSError *error))completion{

    HKQuantityType *lightsClimbedType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierFlightsClimbed];
    NSSortDescriptor *timeSortDescriptor = [[NSSortDescriptor alloc] initWithKey:HKSampleSortIdentifierEndDate ascending:NO];
    HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:lightsClimbedType predicate:[NKHealthKitManager predicateForSamplesToday] limit:HKObjectQueryNoLimit sortDescriptors:@[timeSortDescriptor] resultsHandler:^(HKSampleQuery * _Nonnull query, NSArray<__kindof HKSample *> * _Nullable results, NSError * _Nullable error) {
        
        if(error)
        {
            if (completion) {
                
                completion(0,error);
            }
            
        }else {
            
            double num = 0;
            for (HKQuantitySample *res in results) {
                
                num += [res.quantity doubleValueForUnit:[HKUnit countUnit]];
                
            }
            
            if (completion) {
                
                completion(num,error);
            }
        }
    }];
    [self.healthStore executeQuery:query];

}

// 获取卡路里
- (void)getKilocalorieUnit:(void(^)(double value, NSError *error))completion {

    HKQuantityType *activeEnergyType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierActiveEnergyBurned];
    HKStatisticsQuery *query = [[HKStatisticsQuery alloc] initWithQuantityType:activeEnergyType quantitySamplePredicate:[NKHealthKitManager predicateForSamplesToday] options:HKStatisticsOptionCumulativeSum completionHandler:^(HKStatisticsQuery * _Nonnull query, HKStatistics * _Nullable result, NSError * _Nullable error) {
        
        if(error)
        {
            if (completion) {
                
                completion(0,error);
            }
            
        }else {
            
            HKQuantity *tity = [result sumQuantity];
            double value = [tity doubleValueForUnit:[HKUnit kilocalorieUnit]];
            NSLog(@"卡路里 ---> %.2lf",value);
            if (completion) {
                
                completion(value,error);
            }
        }
        
    }];
    [self.healthStore executeQuery:query];
}

// 获取气压
- (void)getPressure:(void(^)(double value, NSError *error))completion {
    
    // 检测是否支持气压
    if (![CMAltimeter isRelativeAltitudeAvailable]) {
        
        if (completion) {
            NSError *error = NKErrorWithInfo(@"该设备不支持气压计", NSLocalizedDescriptionKey);
            completion(0,error);
            return;
        }
    }
    
    // 开始监测气压
    [self.altimeter startRelativeAltitudeUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMAltitudeData * _Nullable altitudeData, NSError * _Nullable error) {
        
        if (error) {
            
            if (completion) {
                completion(0,error);
            }
            
        }else {
        
            if (completion) {
                
                completion([altitudeData.pressure doubleValue], nil);
            }
        }
        
    }];

}

// 关闭监测气压
- (void)getPressureStop {

    [self.altimeter stopRelativeAltitudeUpdates];
}


- (NSSet *)dataTypeToWrite {

    // 身高
    HKQuantityType *heightType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeight];
    // 体重
    HKQuantityType *weightType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMass];
    // 体温
    HKQuantityType *temperatureType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyTemperature];
    // 步数
    HKQuantityType *stepCountType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount];
    // 楼层
    HKQuantityType *flightsClimbedType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierFlightsClimbed];
    // 步行 + 跑步距离
    HKQuantityType *distance = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceWalkingRunning];
    // 活动能量
    HKQuantityType *activeEnergyType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierActiveEnergyBurned];
    
    return [NSSet setWithObjects:heightType, temperatureType,weightType,stepCountType, flightsClimbedType,distance, activeEnergyType,nil];
}


- (NSSet *)dataTypesRead
{
    // 身高
    HKQuantityType *heightType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeight];
    // 体重
    HKQuantityType *weightType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMass];
    // 体温
    HKQuantityType *temperatureType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyTemperature];
    // 生日
    HKCharacteristicType *birthdayType = [HKObjectType characteristicTypeForIdentifier:HKCharacteristicTypeIdentifierDateOfBirth];
    // 性别
    HKCharacteristicType *sexType = [HKObjectType characteristicTypeForIdentifier:HKCharacteristicTypeIdentifierBiologicalSex];
    // 步数
    HKQuantityType *stepCountType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount];
    // 楼层
    HKQuantityType *flightsClimbedType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierFlightsClimbed];
    // 步行 + 跑步距离
    HKQuantityType *distance = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceWalkingRunning];
    // 活动能量
    HKQuantityType *activeEnergyType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierActiveEnergyBurned];
    
    return [NSSet setWithObjects:heightType, temperatureType,birthdayType,sexType,weightType,stepCountType, flightsClimbedType,distance, activeEnergyType,nil];
}

// 获取当天时间段
+ (NSPredicate *)predicateForSamplesToday {
    
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDate *now = [NSDate date];
    NSDateComponents *components = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay fromDate:now];
    [components setHour:0];
    [components setMinute:0];
    [components setSecond: 0];
    
    NSDate *startDate = [calendar dateFromComponents:components];
    NSDate *endDate = [calendar dateByAddingUnit:NSCalendarUnitDay value:1 toDate:startDate options:0];
    NSPredicate *predicate = [HKQuery predicateForSamplesWithStartDate:startDate endDate:endDate options:HKQueryOptionNone];
    return predicate;

}

#pragma mark -CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {

    CLLocation *newLocation = [locations lastObject];
    
    // 定位精准度小于100米
//    if(newLocation.horizontalAccuracy < kCLLocationAccuracyHundredMeters)
//    {
        if(self.oldLocation)
        {
            // 计算本次定位数据与上次定位数据之间的时间差
            NSTimeInterval dTime = [newLocation.timestamp
                                    timeIntervalSinceDate:self.oldLocation.timestamp];
            // 计算本次定位数据与上次定位数据之间的距离
            CGFloat distance = [newLocation
                                distanceFromLocation:self.oldLocation];
            // 计算移动速度，将米/秒换算成千米/小时，需要乘以3.6
            CGFloat speed = distance / dTime;
            // 如果距离小于1米，则忽略本次数据，直接返回该方法
            if(distance < 1.0f)
            {
                speed = 0;
            }
            _completion(newLocation.altitude, speed, nil);
            
        }
        self.oldLocation = newLocation;
//    }
    
}

@end
